#region Header
//********************************************************************
//	author:         Thomas "zeroflag" Kraemer
//	author email:   zeroflag@zeroflag.de
//	
//	Copyright (C) 2006-2007  Thomas "zeroflag" Kraemer
//	
//	license:	(LGPL)
//	
//		This library is free software; you can redistribute it and/or
//		modify it under the terms of the GNU Lesser General Public
//		License as published by the Free Software Foundation; either
//		version 2.1 of the License, or (at your option) any later version.
//
//		This library is distributed in the hope that it will be useful,
//		but WITHOUT ANY WARRANTY; without even the implied warranty of
//		MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
//		Lesser General Public License for more details.
//
//		You should have received a copy of the GNU Lesser General Public
//		License along with this library; if not, write to the Free Software
//		Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//
//		http://www.gnu.org/licenses/lgpl.html#TOC1
//
//*********************************************************************
#endregion Header

using System;
using System.Drawing;

namespace Enyo
{
	public class Area
	{
		#region Fields
		int left;

		public int Left
		{
			get { return left; }
			set { left = value; }
		}

		int top;

		public int Top
		{
			get { return top; }
			set { top = value; }
		}

		int width;

		public int Width
		{
			get { return width; }
			set { width = value; }
		}

		int height;

		public int Height
		{
			get { return height; }
			set { height = value; }
		}
		#endregion Fields

		#region Properties
		public int Bottom
		{
			get { return this.Top + this.Height; }
			set { this.Height = value - this.Top; }
		}

		public int Right
		{
			get { return this.Left + this.Width; }
			set { this.Width = value - this.Left; }
		}

		public Point Location
		{
			get { return new Point(this.Left, this.Top); }
			set { this.Left = value.X; this.Top = value.Y; }
		}

		public Size Size
		{
			get { return new Size(this.Width, this.Height); }
			set { this.Width = value.Width; this.Height = value.Height; }
		}
		#endregion Properties

		#region Sizing

		#region Include
		/// <summary>
		/// Increases the Area's size to include the given coordinates.
		/// </summary>
		/// <param name="p">The coordinates to include.</param>
		/// <returns>This area's instance for convenience.</returns>
		public Area Include(Point p)
		{
			return this.Include(p.X, p.Y);
		}

		/// <summary>
		/// Increases the Area's size to include the given coordinates.
		/// </summary>
		/// <param name="x">The x-coordinate to include.</param>
		/// <param name="y">The y-coordinate to include.</param>
		/// <returns>This area's instance for convenience.</returns>
		public Area Include(int x, int y)
		{
			if (x < this.Left)
				this.Left = x;
			else if (x > this.Right)
				this.Right = x;
			if (y < this.Top)
				this.Top = y;
			else if (y > this.Bottom)
				this.Bottom = y;
			return this;
		}

		/// <summary>
		/// Creates a copy of the current area and includes the given coordinates in the copy.
		/// </summary>
		/// <param name="x">The x-coordinate to include.</param>
		/// <param name="y">The y-coordinate to include.</param>
		/// <returns>The copied area.</returns>
		public Area CopyInclude(int x, int y)
		{
			return new Area(this).Include(x, y);
		}

		#endregion Include

		#region Grow
		/// <summary>
		/// Increases the Area's size by a given amount.
		/// </summary>
		/// <param name="s">The size to increase by.</param>
		/// <returns>This area's instance for convenience.</returns>
		public Area Grow(Size s)
		{
			return this.Grow(s.Width, s.Height);
		}
		/// <summary>
		/// Increases the Area's size by a given amount.
		/// </summary>
		/// <param name="width">The increase in width.</param>
		/// <param name="height">The increase in height.</param>
		/// <returns>This area's instance for convenience.</returns>
		public Area Grow(int width, int height)
		{
			this.Width += width;
			this.Height += height;
			return this;
		}

		public Area CopyGrow(int width, int height)
		{
			return new Area(this).Grow(width, height);
		}
		#endregion Grow

		#region Operators
		public static Area operator +(Area area, Area area2)
		{
			return area.Include(area2.Left, area2.Top).Include(area2.Right, area2.Bottom);
		}
		public static Area operator +(Area area, Point p)
		{
			return area.Include(p);
		}
		public static Area operator +(Area area, Size s)
		{
			return area.Grow(s);
		}
		#endregion Operators

		#endregion Sizing

		#region Construction
		public Area()
			: this(0, 0, 1, 1)
		{
		}

		public Area(Point p, Size s)
			: this(p.X, p.Y, s.Width, s.Height)
		{
		}

		public Area(Rectangle rect)
			: this(rect.X, rect.Y, rect.Width, rect.Height)
		{
		}

		public Area(Area area)
			: this(area.Left, area.Top, area.Width, area.Height)
		{
		}

		public Area(int left, int top, int width, int height)
		{
			this.Left = left;
			this.Top = top;
			this.Height = height;
			this.Width = width;
		}

		public static implicit operator Rectangle(Area area)
		{
			return new Rectangle(area.Left, area.Top, area.Width, area.Height);
		}

		public static implicit operator Area(Rectangle rect)
		{
			return new Area(rect);
		}
		#endregion Construction
	}
}
